package com.infosystem.demo.services;
import com.infosystem.demo.entities.Employee;
import com.infosystem.demo.entities.Relative;
import com.infosystem.demo.entities.Resume;
import com.infosystem.demo.helpers.IdNumberHelper;
import com.infosystem.demo.models.*;
import com.infosystem.demo.repositories.EmployeeRepository;
import com.infosystem.demo.repositories.RelativeRepository;
import com.infosystem.demo.repositories.ResumeRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.SQLException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service("EmployeeServices")
public class EmployeeServices {
    @Autowired
    private EmployeeRepository employeeRepository;
    @Autowired
    private RelativeRepository relativeRepository;
    @Autowired
    private ResumeRepository resumeRepository;
    @Autowired
    private FileService fileService;

    /************************* employee operations crud ***********************/
    //add employee 添加员工
    public Employee addEmployee(Employee employee) throws SQLException, ParseException {
        IdNumberHelper helper = new IdNumberHelper();
        if (!helper.validateID(employee.getGovId())) {
            System.out.println("The ID number is invalid!");
            return null;
        }
        try {
            return employeeRepository.save(employee);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //get employee by id
    public EmployeeDTOO getEmployeeFullInfoById(String id) throws SQLException {
        // retrieve employee
        Employee employee = employeeRepository.findById(id).orElse(null);
        if (employee == null) {
            System.out.println("Employee not found!");
            return null;
        }
        //fetch resume
        Resume resume = resumeRepository.findByEmployeeId(employee.getId());

        //fetch relatives
        List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());

        EmployeeDTOO employeeDTOO = new EmployeeDTOO(employee);
        if (resume != null) {
            ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
            employeeDTOO.setResume(resumeDTOO);
        }
        employeeDTOO.setRelatives(relatives.stream().map(
                relative -> {
                    RelativeDTOO relativeDTOO = new RelativeDTOO(relative);
                    return relativeDTOO;
                }
            ).collect(Collectors.toList()));
        return employeeDTOO;
    }

    //get employees by name
    public List<EmployeeDTOO> getEmployeeByName(String name) throws SQLException {
        List<Employee> employees = employeeRepository.findByName(name);
        List<EmployeeDTOO> employeeDTOOs = new ArrayList<>();
        for (Employee employee : employees) {
            EmployeeDTOO employeeDTOO = new EmployeeDTOO();
            employeeDTOO.setName(employee.getName());
            employeeDTOO.setEmployeeId(employee.getId());
            employeeDTOO.setGovId(employee.getGovId());
            employeeDTOO.setDepartment(employee.getDepartment());
            employeeDTOO.setEnrollDate(employee.getEnrollDate().toString());
            IdNumberHelper helper = new IdNumberHelper();
            employeeDTOO.setAge(helper.getAge(employee.getGovId()));
            List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());
            List<RelativeDTOO> relativeDTOOs = relatives.stream().map(
                    relative -> {
                        RelativeDTOO relativeDTOO = new RelativeDTOO();
                        relativeDTOO.setName(relative.getName());
                        relativeDTOO.setJobTitle(relative.getJobTitle());
                        relativeDTOO.setPoliticalTitle(relative.getPoliticalTitle());
                        relativeDTOO.setType(relative.getType());
                        return relativeDTOO;
                    }
            ).collect(Collectors.toList());
            employeeDTOO.setRelatives(relativeDTOOs);
            Resume resume = resumeRepository.findByEmployeeId(employee.getId());
            ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
            employeeDTOO.setResume(resumeDTOO);
            employeeDTOOs.add(employeeDTOO);
        }
        return employeeDTOOs;
    }

    //get employees by enrollment date
    public List<EmployeeDTOO> getEmployeeByEnrollDate(Date enroll_date) throws SQLException {
        List<Employee> employees = employeeRepository.findByEnrollDate(enroll_date);
        List<EmployeeDTOO> employeeDTOOs = new ArrayList<>();
        for (Employee employee : employees) {
            EmployeeDTOO employeeDTOO = new EmployeeDTOO();
            employeeDTOO.setName(employee.getName());
            employeeDTOO.setEmployeeId(employee.getId());
            employeeDTOO.setGovId(employee.getGovId());
            employeeDTOO.setDepartment(employee.getDepartment());
            employeeDTOO.setEnrollDate(employee.getEnrollDate().toString());
            IdNumberHelper helper = new IdNumberHelper();
            employeeDTOO.setAge(helper.getAge(employee.getGovId()));
            List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());
            List<RelativeDTOO> relativeDTOOs = relatives.stream().map(
                    relative -> {
                        RelativeDTOO relativeDTOO = new RelativeDTOO();

                        relativeDTOO.setName(relative.getName());
                        relativeDTOO.setJobTitle(relative.getJobTitle());
                        relativeDTOO.setPoliticalTitle(relative.getPoliticalTitle());
                        relativeDTOO.setType(relative.getType());
                        return relativeDTOO;
                    }
            ).collect(Collectors.toList());
            employeeDTOO.setRelatives(relativeDTOOs);
            employeeDTOOs.add(employeeDTOO);
            Resume resume = resumeRepository.findByEmployeeId(employee.getId());
            ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
            employeeDTOO.setResume(resumeDTOO);
        }
        return employeeDTOOs;
    }
    //get employees by age range
    public List<EmployeeDTOO> getEmployeeByAgeRange(int start_age, int end_age) throws SQLException {
        List<Employee> employees = employeeRepository.findAll();
        List<EmployeeDTOO> employeeDTOOs = new ArrayList<>();
        for (Employee employee : employees) {
            // IMPORTANT: 爬取年龄
            IdNumberHelper helper = new IdNumberHelper();
            int age = helper.getAge(employee.getGovId());

            //
            if (age >= start_age && age <= end_age) {
                EmployeeDTOO employeeDTOO = new EmployeeDTOO();
                employeeDTOO.setName(employee.getName());
                employeeDTOO.setEmployeeId(employee.getId());
                employeeDTOO.setGovId(employee.getGovId());
                employeeDTOO.setDepartment(employee.getDepartment());
                employeeDTOO.setEnrollDate(employee.getEnrollDate().toString());
                employeeDTOO.setAge(age);
                List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());
                List<RelativeDTOO> relativeDTOOs = relatives.stream().map(
                        relative -> {
                            RelativeDTOO relativeDTOO = new RelativeDTOO();
                            relativeDTOO.setName(relative.getName());
                            relativeDTOO.setJobTitle(relative.getJobTitle());
                            relativeDTOO.setPoliticalTitle(relative.getPoliticalTitle());
                            relativeDTOO.setType(relative.getType());
                            return relativeDTOO;
                        }
                ).collect(Collectors.toList());
                employeeDTOO.setRelatives(relativeDTOOs);
                employeeDTOOs.add(employeeDTOO);

                Resume resume = resumeRepository.findByEmployeeId(employee.getId());
                ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
                employeeDTOO.setResume(resumeDTOO);
            }
        }
        return employeeDTOOs;
    }
    //get employees by fuzzy name
    public List<EmployeeDTOO> getEmployeeByFuzzyName(String name) throws SQLException {
        //break down name into chars and set parameters
        StringBuilder sb = new StringBuilder();
        sb.append("%");
        for (int i =0; i < name.length(); i++){
            sb.append(name.charAt(i)).append("%");
        }
        String fuzzyName = sb.toString();

        List<Employee> employees = employeeRepository.findByName(fuzzyName);
        List<EmployeeDTOO> employeeDTOOs = new ArrayList<>();
        for (Employee employee : employees) {
            EmployeeDTOO employeeDTOO = new EmployeeDTOO();
            employeeDTOO.setName(employee.getName());
            employeeDTOO.setEmployeeId(employee.getId());
            employeeDTOO.setGovId(employee.getGovId());
            employeeDTOO.setDepartment(employee.getDepartment());
            employeeDTOO.setEnrollDate(employee.getEnrollDate().toString());
            IdNumberHelper helper = new IdNumberHelper();
            employeeDTOO.setAge(helper.getAge(employee.getGovId()));
            List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());
            List<RelativeDTOO> relativeDTOOs = relatives.stream().map(
                    relative -> {
                        RelativeDTOO relativeDTOO = new RelativeDTOO();
                        relativeDTOO.setName(relative.getName());
                        relativeDTOO.setJobTitle(relative.getJobTitle());
                        relativeDTOO.setPoliticalTitle(relative.getPoliticalTitle());
                        relativeDTOO.setType(relative.getType());
                        return relativeDTOO;
                    }
            ).collect(Collectors.toList());
            employeeDTOO.setRelatives(relativeDTOOs);
            employeeDTOOs.add(employeeDTOO);

            Resume resume = resumeRepository.findByEmployeeId(employee.getId());
            ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
            employeeDTOO.setResume(resumeDTOO);
        }
        return employeeDTOOs;
    }

    // get by fuzzy id
    public List<EmployeeDTOO> getEmployeeByFuzzyGovId(String gov_id) throws SQLException {
        //break down name into chars and set parameters
        StringBuilder sb = new StringBuilder();
        sb.append("%");
        for (int i =0; i < gov_id.length(); i++){
            sb.append(gov_id.charAt(i)).append("%");
        }
        String fuzzyGovId = sb.toString();

        List<Employee> employees = employeeRepository.findByGovId(fuzzyGovId);
        List<EmployeeDTOO> employeeDTOOs = new ArrayList<>();
        for (Employee employee : employees){
            EmployeeDTOO employeeDTOO = new EmployeeDTOO();
            employeeDTOO.setName(employee.getName());
            employeeDTOO.setEmployeeId(employee.getId());
            employeeDTOO.setGovId(employee.getGovId());
            employeeDTOO.setDepartment(employee.getDepartment());
            employeeDTOO.setEnrollDate(employee.getEnrollDate().toString());
            IdNumberHelper helper = new IdNumberHelper();
            employeeDTOO.setAge(helper.getAge(employee.getGovId()));
            List<Relative> relatives = relativeRepository.findByEmployeeId(employee.getId());
            List<RelativeDTOO> relativeDTOOs = relatives.stream().map(
                    relative -> {
                        RelativeDTOO relativeDTOO = new RelativeDTOO();
                        relativeDTOO.setName(relative.getName());
                        relativeDTOO.setJobTitle(relative.getJobTitle());
                        relativeDTOO.setPoliticalTitle(relative.getPoliticalTitle());
                        relativeDTOO.setType(relative.getType());
                        return relativeDTOO;
                    }
            ).collect(Collectors.toList());
            employeeDTOO.setRelatives(relativeDTOOs);
            employeeDTOOs.add(employeeDTOO);

            Resume resume = resumeRepository.findByEmployeeId(employee.getId());
            ResumeDTOO resumeDTOO = new ResumeDTOO(resume);
            employeeDTOO.setResume(resumeDTOO);
        }
        return employeeDTOOs;
    }

    //update employee information
    public void updateEmployee(String id, EmployeeDTOI employeeDTOI) {
        Employee employeeToUpdate = employeeRepository.findById(id).orElse(null);
        if (employeeToUpdate == null) {
            System.out.println("Employee not found!");
            return;
        }

        employeeToUpdate.setName(employeeDTOI.getName());
        employeeToUpdate.setGovId(employeeDTOI.getGovId());
        employeeToUpdate.setDepartment(employeeDTOI.getDepartment());
        employeeToUpdate.setEnrollDate(employeeDTOI.getEnrollDate());
        employeeRepository.save(employeeToUpdate);
    }

    public void deleteEmployee(String id) {
        Employee employee = employeeRepository.findById(id).orElse(null);
        if (employee == null) {
            System.out.println("Employee not found!");
            return;
        }
        employeeRepository.delete(employee);
    }

    public void batchDeleteEmployee(List<String> ids) {
        for (String id : ids) {
            Employee employee = employeeRepository.findById(id).orElse(null);
            if (employee == null) {
                System.out.println("Employee not found!");
                return;
            }
            employeeRepository.delete(employee);
        }
    }

    /************************** relatives operations crud ***********************/
    public void addRelative(RelativeDTOI relativeDTOI) {
        //find the employee
        Employee employee = employeeRepository.findById(relativeDTOI.getEmployeeId()).orElse(null);
        if (employee == null) {
            System.out.println("Employee not found!");
            return;
        }
        //link the relative
        Relative relative = new Relative(relativeDTOI);
        relative.setEmployee(employee);
        relativeRepository.save(relative);
    }

    public void updateRelative(String id, RelativeDTOI relativeDTOI) {
        Relative relativeToUpdate = relativeRepository.findById(id).orElse(null);
        if (relativeToUpdate == null) {
            System.out.println("Relative not found!");
            return;
        }
        relativeToUpdate.setName(relativeDTOI.getName());
        relativeToUpdate.setJobTitle(relativeDTOI.getJobTitle());
        relativeToUpdate.setPoliticalTitle(relativeDTOI.getPoliticalTitle());
        relativeToUpdate.setType(relativeDTOI.getType());
        relativeRepository.save(relativeToUpdate);
    }

    public List<RelativeDTOO> getRelativeByEmployeeId(String employee_id) {
        List<Relative> relatives = relativeRepository.findByEmployeeId(employee_id);
        if (relatives == null) {
            System.out.println("Relative not found!");
            return null;
        }
        List<RelativeDTOO> relativeDTOOS = new ArrayList<>();
        for (Relative relative : relatives){
            RelativeDTOO relativeDTOO = new RelativeDTOO(relative);
        }
        return relativeDTOOS;
    }

    public List<RelativeDTOO> getRelativeByJobTitle(String jobTitle) {
        List<Relative> relatives = relativeRepository.findByJobTitle(jobTitle);
        if (relatives == null) {
            System.out.println("Relative not found!");
            return null;
        }
        List<RelativeDTOO> relativeDTOOS = new ArrayList<>();
        for (Relative relative : relatives){
            RelativeDTOO relativeDTOO = new RelativeDTOO(relative);
        }
        return relativeDTOOS;
    }

    public List<RelativeDTOO> getRelativeByPoliticalTitle(String politicalTitle){
        List<Relative> relatives = relativeRepository.findByPoliticalTitle(politicalTitle);
        if (relatives == null) {
            System.out.println("Relative not found!");
            return null;
        }
        List<RelativeDTOO> relativeDTOOS = new ArrayList<>();
        for (Relative relative : relatives){
            RelativeDTOO relativeDTOO = new RelativeDTOO(relative);
        }
        return relativeDTOOS;
    }

    public List<RelativeDTOO> getRelativeByFuzzyName(String name) {
        //break down name into chars and set parameters
//        StringBuilder sb = new StringBuilder();
//        sb.append("%");
//        for (int i =0; i < name.length(); i++){
//            sb.append(name.charAt(i)).append("%");
//        }
//        String fuzzyName = sb.toString();


        // List<Relative> relatives = relativeRepository.findByFuzzyName(fuzzyName);
        List<Relative> relatives = relativeRepository.findByNameContaining(name);
        if (relatives.isEmpty()) {
            System.out.println("Relative not found!");
            return null;
        }
        List<RelativeDTOO> relativeDTOOs = new ArrayList<>();
        for (Relative relative : relatives){
            RelativeDTOO relativeDTOO = new RelativeDTOO(relative);
            relativeDTOOs.add(relativeDTOO);
        }
        return relativeDTOOs;
    }

//    public void deleteRelativeByEmployee(String employee_id, int relativeIndex) {
//        List<Relative> relatives = relativeRepository.findByEmployeeId(employee_id);
//        if (relatives == null) {
//            System.out.println("Relative not found!");
//            return;
//        }
//        // delete relativeIndex'th relative
//        relativeRepository.delete(relatives.get(relativeIndex));
//    }

    public void deleteRelativeById(String id){
        Relative relative = relativeRepository.findById(id).orElse(null);
        if (relative == null) {
            System.out.println("Relative not found!");
            return;
        }
        relativeRepository.delete(relative);
    }
    public void batchDeleteRelative(List<String> ids) {
        for (String id : ids) {
            Relative relative = relativeRepository.findById(id).orElse(null);
            if (relative == null) {
                System.out.println("Relative not found!");
                return;
            }
            relativeRepository.delete(relative);
        }
    }

    /******************* resume operations crud ***********************/
    public void uploadResume(String employee_id, ResumeDTOI resumeDTOI) {
        //find the employee
        Employee employee = employeeRepository.findById(employee_id)
                .orElse(null);
        if (employee == null) {
            System.out.println("Employee not found!");
            return;
        }
        //upload resume, get the resume url,
        String uploadedUrl = fileService.uploadToLocal(resumeDTOI.getResume(), "resume");
        // store into database
        Resume resume = new Resume(employee_id, uploadedUrl);
        resume.setEmployee(employee);
        resumeRepository.save(resume);
    }

    public void deleteResume(String employee_id) {
        Resume resume = resumeRepository.findByEmployeeId(employee_id);
        if (resume == null) {
            System.out.println("Resume not found!");
            return;
        }
        resumeRepository.delete(resume);
    }

    public ResumeDTOO getResumeByEmployeeId(String employee_id) {
        Resume resume = resumeRepository.findByEmployeeId(employee_id);
        if (resume == null) {
            System.out.println("Resume not found!");
            return null;
        }
        return new ResumeDTOO(resume);
    }
}